package au.edu.qut.bpm.genbinder.genetic.other;

public class testrepair {
	/*
		//LinkedHashMap<Activity, Long> mpActST = new LinkedHashMap<Activity, Long>();
	//public static LinkedHashMap<Activity, Long> mpNewActST = new LinkedHashMap<Activity, Long>();
	ConcreteEventLog newLog = log.clone();
	
	LinkedList<Activity> listAct = new LinkedList<Activity>(newLog.getAllActivity());
	
	HashMap<Resource, Long> mpResLastET = new HashMap<Resource, Long>();
	//listAct = newLog.getSortedActivity(listAct);
	
	for (Activity x : listAct) {
		mpActST.put(x, x.getStartTime());
		//System.out.println("st-" + x.getStartTime() + "-" + z++);
	}
	
	for (Resource y : newLog.getAbstractLog().getResources()) {
		mpResLastET.put(y, 0L);
	}
	mpActST = sortByComparator(mpActST);
	//printMap(mpActST);
	ConcreteEventLog newFixedLog = new ConcreteEventLog(log.getAbstractLog());
	
	for (Map.Entry entry : mpActST.entrySet()) {
		Activity a = (Activity) entry.getKey();
		Resource r = a.getResource().iterator().next();
		if (mpResLastET.get(r) < (long) entry.getValue()) {
			mpNewActST.put(a, (long) entry.getValue());
			mpResLastET.put(r, (long) entry.getValue() + a.getDuration());
		} else {
			mpNewActST.put(a, mpResLastET.get(r));
			mpResLastET.put(r, mpResLastET.get(r) + a.getDuration());
		}
		newLog.setActivityStart(a, mpNewActST.get(a));
		newLog.setActivityResources(a, a.getResource());
		//System.out.println("Value : " + entry.getValue() + " Key : " + entry.getKey());
	}
	mpNewActST = sortByComparator(mpNewActST);
	MainPanel.log = new ConcreteEventLog(newLog.getAbstractLog());
	MainPanel.showLog(MainPanel.log);
	//newLog.boundStartTime = new HashMap<Activity, Long>(mpNewActST);
	
	return newLog;
	
	//LogRepairFactory factory = new LogRepairFactory(newLog.getAbstractLog());
	//ConcreteEventLog newReturnedLog = factory.generateRandomCandidate(true, new Random());
	
	//return newReturnedLog;
	
	*/
	
	
	
	/*
	List<Activity> entries =  new LinkedList<Activity>(newLog.getAllActivity());
	Collections.sort(entries, new Comparator<Activity>() {
		public int compare(Activity a, Activity b){
			return ((Long) a.getStartTime()).compareTo((Long) b.getStartTime());
		}
	});
	
	Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
	for (Activity entry : entries) {
		sortedMap.put(entry.getKey(), entry.getValue());
	}
	
	*/
	//int z = 0;
	
	
	
	
	
	//this.boundStartTime = new HashMap<Activity, Long>(newLog.boundStartTime);
	//this.boundResources = new HashMap<Activity, Set<Resource>>(newLog.boundResources);
	
	
	//ConcreteEventLog newLog = new ConcreteEventLog(log.getAbstractLog());
	
	//BST = log.getBoundStartTime();
	///*
	//for (Entry<Activity, Long> c : bST.entrySet()) {
	//	System.out.println(c.getKey() + " = " + c.getValue());
	//}
	/*
	int minute = 1000 * 60;
	XLog xesLog = LogToXESConverter.createLog(log, CaseListPanel.ZEROBLOCK, GeneticBinder.BLOCK_DURATION / minute);
	XSerializer serializer = new XesXmlSerializer();
	File file = new File("logs/repairexport.xes");
	
	try {
		FileOutputStream fos = new FileOutputStream(file, false);
		serializer.serialize(xesLog, fos);
		fos.flush();
		fos.close();
	} catch (Exception e1) {
		e1.printStackTrace();
	}
	
	ConcreteEventLog newLog = null;
	
	XParser parser = new XesXmlParser();
	List<XLog> l;
	try {
		l = parser.parse(new File("logs/repairexport.xes"));
		
		XLog xlog = l.get(0);
		//ConcreteEventLog nLog = XESToLogConverter.createLog(xlog);
		newLog = XESToLogConverter.createLog(xlog);
		//newLog = new ConcreteEventLog(nLog.getAbstractLog());
		//newLog.setBoundStartTime(bST);
		
		//System.out.println("getAL-" + newLog.getAbstractLog().getActivities());
		//newLog.setAbstractLog(newLog.getAbstractLog());
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	

	file.delete();
	//*/
	//long zeroBlock = DiscreteLogConverter.timeToLowerBlock(log.getLogArrival(), 0, GeneticBinder.BLOCK_DURATION) * GeneticBinder.BLOCK_DURATION;
	
	//log = DiscreteLogConverter.makeDiscrete(log, zeroBlock, GeneticBinder.BLOCK_DURATION);

	//CaseListPanel.TIMETOPIXELS = 30;		//block width per minute
	//CaseListPanel.ZEROBLOCK = zeroBlock;
	//this.log = log;
	//
	//int repairCount = 0;
	
	//ConcreteEventLog newLog = log.clone();
	/*
	while (!(newLog.isLogSafe() || newLog.isLogValid())) {
		LinkedList<Activity> listOfAllActs = new LinkedList<Activity>(newLog.getAllActivity());
		listOfAllActs = newLog.getSortedActivity(listOfAllActs);
		
		Map<Case, LinkedList<Activity>> hmapCaseActs = new LinkedHashMap<Case, LinkedList<Activity>>();

		for (Case c : newLog.getAbstractLog().getCases()) {
			List<Activity> fixedActPrecedence = c.getOrderedTrace();
			LinkedList<Activity> listActPerCase = new LinkedList<Activity>();
			
			for (Activity a : fixedActPrecedence) {
				listActPerCase.add(a);
			}
			hmapCaseActs.put(c, listActPerCase);
		}
		for (Activity a : listOfAllActs) {
			long activityStartTime = newLog.getActivityStart(a);
			long activityEndTime = newLog.getActivityEnd(a);
			Set<Resource> res = new HashSet<Resource>(a.getResource());
			LinkedList<Activity> listClashingActs = new LinkedList<Activity>(newLog.getClashingActivitiesWithin(a, activityStartTime, activityEndTime, res));
			for (Activity a2 : newLog.getSortedActivities(listClashingActs)) {
				long originalStartTime = newLog.getActivityStart(a2);
				long newStartTime = activityEndTime;
				long timeDifference = newStartTime - originalStartTime;
				Case activityCase = a2.getCase();
				Set<Resource> res2 = new HashSet<Resource>(a2.getResource());
				LinkedList<Activity> listActInCase = new LinkedList<Activity>();
				
				for (Entry<Case, LinkedList<Activity>> c : hmapCaseActs.entrySet()) {
					if (c.getKey().equals(activityCase)) {
						listActInCase = c.getValue();
					}
				}
				
				boolean clashAgain = true;
				
				while (clashAgain) {
					LinkedList<Activity> listClashingActsAfterShift = 
							new LinkedList<Activity>(newLog.getClashingActivitiesWithin(a2, newStartTime, newLog.getActivityDuration(a2) + newStartTime + timeDifference, res2));
					
					if (listClashingActsAfterShift.size() == 0) {
						newLog.setActivityStart(a2, newStartTime);
						//boundStartTime.put(a2, newStartTime);
						clashAgain = false;
					} else {

						newStartTime = newLog.getActivityEnd(listClashingActsAfterShift.get(0)); //fix this to detect the absolute last activity end among all the list (for loop)
						timeDifference = newStartTime - originalStartTime;
					}
					
				}
				
				if (!clashAgain) {
					for (Activity actInCase : listActInCase) {
						if (!actInCase.equals(a2)) {
							if (newLog.getActivityStart(actInCase) >= activityStartTime) {
								newLog.setActivityStart(actInCase, newLog.getActivityStart(actInCase) + timeDifference);
								//boundStartTime.put(actInCase, newLog.getActivityStart(actInCase) + timeDifference);
							}
						}
						
					}
				}
			}
		}
		//newLog.boundStartTime = new HashMap<Activity, Long>(boundStartTime);
		/*
		if (repairCount > 5) {
			System.out.println("give up");
			return newLog;
		} else {
			repairCount++;
		}
		//*/
		//break;
	//}
	//return newLog;
	/*
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static LinkedHashMap sortByComparator(LinkedHashMap unsortMap) {
		 

		List list = new LinkedList(unsortMap.entrySet());
 
		// sort list based on comparator
		Collections.sort(list, new Comparator() {
			public int compare(Object o1, Object o2) {
				return ((Comparable) ((Map.Entry) (o1)).getValue()).compareTo(((Map.Entry) (o2)).getValue());
			}
		});
 
		// put sorted list into map again
                //LinkedHashMap make sure order in which keys were inserted
		LinkedHashMap sortedMap = new LinkedHashMap();
		for (Iterator it = list.iterator(); it.hasNext();) {
			Map.Entry entry = (Map.Entry) it.next();
			sortedMap.put(entry.getKey(), entry.getValue());
		}
		return sortedMap;
	}
 
	@SuppressWarnings("rawtypes")
	public static void printMap(LinkedHashMap<Activity, Long> map){
		for (Map.Entry entry : map.entrySet()) {
			System.out.println("Value : " + entry.getValue() + " Key : " + entry.getKey());
		}
	}
	*/
/*
public long getActivityStart(Activity activity) {
	
	//long a = this.boundStartTime.get(activity);
	//if (this.boundStartTime.get(activity) == null) {
		//System.out.println("problemhere-" + activity.getId() + " = " + this.boundStartTime.containsKey(activity));
	//}
	
	return BST.get(activity);
}

public long getActivityEnd(Activity activity) {
	return getActivityStart(activity) + getActivityDuration(activity);
}

public long getActivityDuration(Activity activity) {
	return activity.getDuration();
}

public void setActivityStart(Activity activity, long time) {
	BST.put(activity, time);
}
*/
	
	/*
	//fixedLog = log;
	//boolean resourceClash = true;
	
	//while (!(fixedLog.isLogSafe() || fixedLog.isLogValid())) {
	//while (resourceClash) {

	LinkedList<Activity> listAct = new LinkedList<Activity>();
	
	//PUT ALL THE ACTIVITIES INTO A CASE-LISTOFACT MAPPING
	Map<Case, LinkedList<Activity>> hmapCaseActs = new LinkedHashMap<Case, LinkedList<Activity>>();

	for (Case c : log.getAbstractLog().getCases()) {
		List<Activity> fixedActPrecedence = c.getOrderedTrace();
		LinkedList<Activity> listActPerCase = new LinkedList<Activity>();
		
		for (Activity a : fixedActPrecedence) {
			listAct.add(a);
			listActPerCase.add(a);
		}
		hmapCaseActs.put(c, listActPerCase);
	}
	
	//PUT ALL THE ACTIVITIES INTO A RESOURCE-LISTOFACT MAPPING
	Map<Resource, LinkedList<Activity>> hmapResourceActs = new LinkedHashMap<Resource, LinkedList<Activity>>();
	
	for (Resource r : fixedLog.getAbstractLog().getResources()) {
		LinkedList<Activity> listActPerResource = new LinkedList<Activity>();
		for (Activity a : listAct) {
			if (a.getResource().equalsIgnoreCase(r.getId())) {
				listActPerResource.add(a);
			}
		}
		hmapResourceActs.put(r, listActPerResource);
	}
	
	LinkedList<Activity> listCheckedActivities = new LinkedList<Activity>();
	//Map<Resource, Long> hmapResourceLastEndTime = new LinkedHashMap<Resource, Long>();
	
	//FOR EACH RESOURCE
	for (Entry<Resource, LinkedList<Activity>> r : hmapResourceActs.entrySet()) {
		LinkedList<Activity> listResourceActs = r.getValue();
		
		//FOR EACH ACTIVITY IN THAT PARTICULAR RESOURCE
		for (Activity a : fixedLog.getSortedActivities(listResourceActs)) {
			long activityStartTime = fixedLog.getActivityStart(a);
			long activityEndTime = fixedLog.getActivityEnd(a);
			Resource res = r.getKey();
			
			LinkedList<Activity> listClashingActs = new LinkedList<Activity>(fixedLog.getClashingActivitiesWithin(a, activityStartTime, activityEndTime, res));
			
			System.out.println(a + "..." + activityStartTime + "-" + activityEndTime + "..." + listClashingActs.toString());
			
			for (Activity a2 : fixedLog.getSortedActivities(listClashingActs)) {
				long originalStartTime = fixedLog.getActivityStart(a2);
				
				if (originalStartTime >= activityStartTime && originalStartTime <= activityEndTime ) {
					long newStartTime = activityEndTime;
					long timeDifference = newStartTime - originalStartTime;
					Case activityCase = a2.getCase();
					LinkedList<Activity> listActInCase = new LinkedList<Activity>();
					
					for (Entry<Case, LinkedList<Activity>> c : hmapCaseActs.entrySet()) {
						if (c.getKey().equals(activityCase)) {
							listActInCase = c.getValue();
						}
					}
					//System.out.println("yes2");
					
					boolean actClash1 = true;
					Resource resClash1 = new Resource(a2.getResource());
					
					while (actClash1 && (listCheckedActivities.size() != 0)) {
						//System.out.println("yes4");
						for (Activity checkActClash : listCheckedActivities) {
							//System.out.println("yes3");
							LinkedList<Activity> listClashingActsAfterShift = new LinkedList<Activity>(fixedLog.getClashingActivitiesWithin(checkActClash, newStartTime, fixedLog.getActivityDuration(a2) + newStartTime, resClash1));
							//System.out.println("yes");
							if (listClashingActsAfterShift.size() == 0) {
								fixedLog.setActivityStart(a2, newStartTime);
								actClash1 = false;
							} else {
								///*
								if (hmapResourceLastEndTime.containsKey(resClash1)) {
									newStartTime = newStartTime + hmapResourceLastEndTime.get(resClash1);
									
								} else {
									newStartTime = newStartTime + 1;
								}
								fixedLog.setActivityStart(a2, newStartTime);
								actClash1 = false;
								//
								newStartTime = newStartTime + 1;
							}
						}
					}
					
					//System.out.println("yes5");
					
					for (Activity a3 : listActInCase) {
						long act3StartTime = fixedLog.getActivityStart(a3);
						//System.out.println("yes6");
						//if (act3StartTime >= activityStartTime && act3StartTime <= activityEndTime) {
						//	fixedLog.setActivityStart(a2, activityEndTime);
						//} else if (act3StartTime > activityEndTime) {
						if (a2.equals(a3))
							;
						else if (act3StartTime >= activityStartTime) {
							
							boolean actClash2 = true;
							Resource resClash2 = new Resource(a3.getResource());
							
							while (actClash2 && (listCheckedActivities.size() != 0)) {
								for (Activity checkActClash : listCheckedActivities) {
									LinkedList<Activity> listClashingActsAfterShift2 = 
											new LinkedList<Activity>(fixedLog.getClashingActivitiesWithin(checkActClash, act3StartTime + timeDifference, fixedLog.getActivityDuration(a3) + act3StartTime + timeDifference, resClash2));
									
									if (listClashingActsAfterShift2.size() == 0) {
										fixedLog.setActivityStart(a3, act3StartTime + timeDifference);
										actClash2 = false;
									} else {
										/*
										if (hmapResourceLastEndTime.containsKey(resClash1)) {
											timeDifference = newStartTime + hmapResourceLastEndTime.get(resClash1);
											
											
										} else {
											timeDifference = timeDifference + 1;
										}
										fixedLog.setActivityStart(a3, timeDifference);
										actClash2 = false;
										//
										timeDifference = timeDifference + 1;
									}
								}
							}
						}
							
						//}
					}
					
				}
				System.out.println("not within timeframe");
			}
			listCheckedActivities.add(a);
			Resource checkedRes = new Resource(a.getResource());
			//hmapResourceLastEndTime.put(checkedRes, fixedLog.getActivityEnd(a));
		}
    }
	//*/
	/*
	for (Case c : fixedLog.getAbstractLog().getCases()) {
		if (fixedLog.isCaseNonOverUtilizedResources(c)) {
			resourceClash = false;
		}
	}//*/
	
	//GeneticBinder.log = fixedLog;
	//}
	
	
	
	/*//====my own's version 2==
	this.log = log;
	AbstractLog al = new AbstractLog("1");
	Binding b = new Binding();
	ConcreteEventLog newLog = new ConcreteEventLog(al);
	newLog.setBinding(b);
	
	
	for (Case c : log.getAbstractLog().getCases()) {
		List<Activity> newOrder = c.getOrderedTrace();
		
		for (Activity a : newOrder) {
			System.out.println("1-" + log.getActivityStart(a) + " 2-" + log.getActivityEnd(a) + " 3-" + listActivity + " 4-" + a.getResource());
			boolean resourceUtilized = checkWhetherResourceIsUtilizedWithin(log.getActivityStart(a), log.getActivityEnd(a), listActivity, a.getResource()); //might have a problem with empty/null list.
			System.out.println(resourceUtilized);
			
			if (resourceUtilized) {
				//List<Activity> closedListActivity = new ArrayList();
				long latestEndTime = 0;
				
				for (Activity la : listActivity) {
					if (la.getResource().equalsIgnoreCase(a.getResource())) {
						if (newLog.getActivityEnd(la) > latestEndTime) {
							latestEndTime = newLog.getActivityEnd(la);
						}
					}
				}
				
				boolean resourceUtilizedDoubleCheck = newLog.checkWhetherResourceIsUtilizedWithin(latestEndTime, latestEndTime + a.getDuration(), listActivity, a.getResource());
				
				if (!resourceUtilizedDoubleCheck){
					Set<Resource> resource = new HashSet<Resource>();
					Resource res = new Resource(a.getResource());
					resource.add(res);
					
	
					newLog.addNewActivity(a.getId(), a.getName(), a.getCase(), a.getTask(), a.getDuration(), a.getResource());
					newLog.setActivityStart(a, latestEndTime);
					newLog.setActivityResources(a, resource);

					listActivity.add(a);
				}
				
				
			} else {
				//Activity activity = new Activity(a.getId(), a.getName(), a.getCase(), a.getTask(), nextEventTime - eventTime, resource, event.getAttributes());
				//BindingActivity ba = new BindingActivity(a.getId(), a.getName(), a.getCase(), a.getTask(), a.getDuration(), a.getResource());
				//Resource res = null;

				Set<Resource> resource = new HashSet<Resource>();
				Resource res = new Resource(a.getResource());
				resource.add(res);
				
				System.out.println(a.getId() + a.getName() + a.getCase() + a.getTask() + a.getDuration() + a.getResource());
				
				newLog.addNewActivity(a.getId(), a.getName(), a.getCase(), a.getTask(), a.getDuration(), a.getResource());
				newLog.setActivityStart(a, log.getActivityStart(a));
				newLog.setActivityResources(a, resource);

				listActivity.add(a);
			}
		}
	}
	//*/
	
	//====jochen's suggestion===
	
	
	/*
	Set<Activity> setAct = new HashSet<Activity>();
	
	for (Case c : log.getAbstractLog().getCases()) {
		List<Activity> newOrder = c.getOrderedTrace();
		setAct.addAll(newOrder);
	}
	
	LinkedList listOfActivity = new LinkedList(setAct);
	LinkedList<Activity> sortedActivity = fixedLog.getSortedActivity(listOfActivity);
	System.out.println(sortedActivity.size());
	
	//for (Activity sa : sortedActivity) {
	//	newLog.setActivityStart(sa, 0);
	//}
	
	for (Activity sa : sortedActivity) {
		//Set<Resource> alreadyUsed = log.getResourcesUtilizedWithin(log.getActivityStart(sa), log.getActivityEnd(sa));
		boolean resourceClash = false;
		resourceClash = log.checkWhetherResourceIsUtilizedWithin(log.getActivityStart(sa), log.getActivityEnd(sa), sortedActivity, sa.getResource());
		System.out.println("act-" + sa.getId() + " res-" + sa.getResource() + " clash-" + resourceClash);
		
		long availableStartTime = log.getActivityEnd(sa);
		
		if (resourceClash) {
			
			boolean availableResource = false;
			while (!availableResource) {
				availableResource = log.checkWhetherResourceIsUtilizedWithin(availableStartTime, (availableStartTime + log.getActivityDuration(sa)), sortedActivity, sa.getResource());
				
				if (availableResource) {
					newLog.setActivityStart(sa, availableStartTime);
				} else {
					availableStartTime++;
				}
				System.out.println(sa + " " + availableStartTime);
			}
			
			resourceClash = false;
		}
	}
	//*/
	
	
	//======my own version 1========
	/*
	Random rng = new Random();
	Set<Activity> setAct = new HashSet<Activity>(fixedLog.getAllActivity());
	System.out.println("repairStart");
	int y = 0;
	for (long t = fixedLog.getLogArrival(); t < fixedLog.getLogEnd(); t++) {
		System.out.println("COUNT-" + y++);
		Map<Activity, String> setActWithStartTime = new HashMap<Activity, String>();
		for (Activity a : setAct) {
			if (fixedLog.getActivityStart(a) == t) {
				setActWithStartTime.put(a, a.getResource());
			}
		}
		System.out.println("repair1");
		int z = 0;
		for (Entry<Activity, String> entry : setActWithStartTime.entrySet()) {
			System.out.println("count-" + z++);
			Set<Resource> alreadyUsed = fixedLog.getResourcesUtilizedWithin(fixedLog.getActivityStart(entry.getKey()), fixedLog.getActivityEnd(entry.getKey()), entry.getKey().getCase());
			boolean resourceClash = false;
			
			for (Resource res : alreadyUsed)
				if (alreadyUsed.contains(res))
					resourceClash = true;
			System.out.println("repair2");
			if (resourceClash) {
				Set<Set<Resource>> possible = fixedLog.getAbstractLog().getTaskResourceSetMap().get(entry.getKey().getTask());
				Set<Set<Resource>> available = new HashSet<Set<Resource>>(possible);
				System.out.println(available.size());
				for (Resource r : alreadyUsed)
					for (Set<Resource> rs : possible)
						if (rs.contains(r))
							available.remove(rs);
				System.out.println(available.size());	
				System.out.println("repair3");
				if (available.size() == 0) {
					fixedLog.setActivityStart(entry.getKey(), (fixedLog.getActivityStart(entry.getKey()) + 1));
					System.out.println("DelayTime");
				} else {
					int item = rng.nextInt(available.size());
					int i = 0;
					for (Set<Resource> r : available) {
						if (i == item) {
							fixedLog.setActivityResources(entry.getKey(), r);
							break;
						}
						i++;
					}
					System.out.println("ChangeResource");
				}
				resourceClash = false;
			}
		}
	}
	
	//===========
	/*
	List<Set<Activity>> v = fixedLog.getLogViolatingActivities();
	Set<Activity> actSet = v.get(2);
	
	Random rng = new Random();
	
	for (Activity a : actSet) {
		//System.out.println("iter-" + a.getTask());
		  
		Set<Set<Resource>> possible = fixedLog.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
		Set<Set<Resource>> available = new HashSet<Set<Resource>>(possible);
		Set<Resource> alreadyUsed = fixedLog.getResourcesUtilizedWithin(fixedLog.getActivityStart(a), fixedLog.getActivityEnd(a), a.getCase());
		
		for (Resource r : alreadyUsed)
			for (Set<Resource> rs : possible)
				if (rs.contains(r))
					available.remove(rs);
		if (available.size() == 0) {
			//return false;
			//System.out.println("false");
		} else {
			int item = rng.nextInt(available.size());
			int i = 0;
			for (Set<Resource> r : available) {
				if (i == item) {
					fixedLog.setActivityResources(a, r);
					break;
				}
				i++;
			}
		}
	}
	*/
	
	/*
	if (!this.performTimeRepair(fixedLog) || !this.performResourceRepair(fixedLog)) {
		fixedLog = this.performFallbackRepair(fixedLog);
	}
	//*/
	
	//return newLog
	

/*
public boolean checkWhetherResourceIsUtilizedWithin(long start, long end, List<Activity> sortedActivity, String res) {
	System.out.println("test");
	System.out.println("fasle" + sortedActivity.size());
	System.out.println("test2");
	if (sortedActivity.size() == 0) {
		return false;
	}
	
	boolean resourceAlreadyUtilized = false;
	
	Set<String> alreadyUsed = new HashSet<String>();
	
	for (Activity a : sortedActivity)
		if (isActivityWithin(a, start, end))
			alreadyUsed.add(a.getResource());//alreadyUsed.addAll(getActivityResources(a));
	
	if (alreadyUsed.contains(res))
		resourceAlreadyUtilized = true;
	
	return resourceAlreadyUtilized;
}

public boolean isActivityWithin(Activity activity, long start, long stop) {
	return getActivityStart(activity) < stop && getActivityEnd(activity) > start;
}

public long getActivityStart(Activity activity) {
	int a = listActivity.indexOf(activity);
	Activity act = listActivity.get(a);

	return log.getActivityStart(act);
}

public long getActivityEnd(Activity activity) {
	int a = listActivity.indexOf(activity);
	Activity act = listActivity.get(a);
	
	return getActivityStart(activity) + log.getActivityDuration(act);
}

public boolean performTimeRepair(ConcreteEventLog log) {
	// Time based repairs
	System.out.println("time");
	for (Case c : log.getAbstractLog().getCases()) {
		if (log.isCaseOrdered(c)) {
			// This case is ordered, but are there overlaps?
			if (log.isCaseNonOverlapping(c))
				continue;
			List<Activity> sortedTrace = log.getSortedTrace(c);
			long latestEnd = log.getActivityEnd(sortedTrace.get(0));
			for (int a = 1; a < sortedTrace.size(); a++) {
				if (log.getActivityStart(sortedTrace.get(a)) < latestEnd)
					log.setActivityStart(sortedTrace.get(a), latestEnd);
				latestEnd = log.getActivityEnd(sortedTrace.get(a));
			}
		} else {
			// This case is unordered, let's fix it
			List<Activity> newOrder = c.getOrderedTrace();
			for (int a = 0; a < newOrder.size(); a++) {
				Activity act = newOrder.get(a);
				long startTime = a == 0
						? c.getArrival()
						: log.getActivityEnd(act);
				log.setActivityStart(act, startTime);
			}
		}
	}
	return true;
}

public boolean performResourceRepair(ConcreteEventLog log) {
	// Resource based repairs
	System.out.println("res");
	Random rng = new Random(); // Meh...
	for (Case c : log.getAbstractLog().getCases()) {
		if (log.isCaseNonOverUtilizedResources(c))
			continue;
		for (Activity a : c.getActivities()) {
			Set<Set<Resource>> possible = log.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
			Set<Set<Resource>> available = new HashSet<Set<Resource>>(possible);
			Set<Resource> alreadyUsed = log.getResourcesUtilizedWithin(log.getActivityStart(a), log.getActivityEnd(a), c);
			for (Resource r : alreadyUsed)
				for (Set<Resource> rs : possible)
					if (rs.contains(r))
						available.remove(rs);
			if (available.size() == 0) {
				return false;
				/*
				boolean freeResourceFound = false;
				int delayTime = 1;
				//long newActStartTime = 0;
				
				while (!freeResourceFound) {
					Set<Set<Resource>> possibleRes = log.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
					Set<Set<Resource>> availableRes = new HashSet<Set<Resource>>(possible);
					Set<Resource> alreadyUsedRes = log.getResourcesUtilizedWithin(log.getActivityStart(a) + delayTime, log.getActivityEnd(a) + delayTime, c);
					for (Resource r : alreadyUsedRes)
						for (Set<Resource> rs : possibleRes)
							if (rs.contains(r))
								availableRes.remove(rs);
					
					if (availableRes.size() == 0) {
						delayTime++;
					} else {
						int item = rng.nextInt(availableRes.size());
						int i = 0;
						for (Set<Resource> r : availableRes) {
							if (i == item) {
								log.setActivityResources(a, r);
								log.setActivityStart(a, log.getActivityStart(a) + delayTime);
								break;
							}
							i++;
						}
						freeResourceFound = true;
					}
				}
				System.out.println("false");
				
				//log.setActivityStart(a, (log.getActivityStart(a) + 1));
			
			} else {
				int item = rng.nextInt(available.size());
				int i = 0;
				for (Set<Resource> r : available) {
					if (i == item) {
						log.setActivityResources(a, r);
						break;
					}
					i++;
				}
			}
		}
	}
	return true;
}

public ConcreteEventLog performFallbackRepair(ConcreteEventLog fixedLog) {
	System.out.println("fallback");
	
	LogGreedyFactory factory = new LogGreedyFactory(fixedLog.getAbstractLog(), false);
	fixedLog = factory.generateRandomCandidate(new Random());

	if (!fixedLog.isLogSafe())
		System.err.println("Solution was still not safe after last resort repair!");

	return fixedLog;
}
//*/
	/*
	public boolean performTimeRepair(ConcreteEventLog log) {
		// Time based repairs
		for (Case c : log.getAbstractLog().getCases()) {
			if (log.isCaseOrdered(c)) {
				// This case is ordered, but are there overlaps?
				if (log.isCaseNonOverlapping(c))
					continue;
				List<Activity> sortedTrace = log.getSortedTrace(c);
				long latestEnd = log.getActivityEnd(sortedTrace.get(0));
				for (int a = 1; a < sortedTrace.size(); a++) {
					if (log.getActivityStart(sortedTrace.get(a)) < latestEnd)
						log.setActivityStart(sortedTrace.get(a), latestEnd);
					latestEnd = log.getActivityEnd(sortedTrace.get(a));
				}
			} else {
				// This case is unordered, let's fix it
				List<Activity> newOrder = c.getOrderedTrace();
				for (int a = 0; a < newOrder.size(); a++) {
					Activity act = newOrder.get(a);
					long startTime = a == 0
							? c.getArrival()
							: log.getActivityEnd(act);
					log.setActivityStart(act, startTime);
				}
			}
		}
		return true;
	}

	public boolean performResourceRepair(ConcreteEventLog log) {
		// Resource based repairs
		Random rng = new Random(); // Meh...
		for (Case c : log.getAbstractLog().getCases()) {
			if (log.isCaseNonOverUtilizedResources(c))
				continue;
			for (Activity a : c.getActivities()) {
				Set<Set<Resource>> possible = log.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
				Set<Set<Resource>> available = new HashSet<Set<Resource>>(possible);
				Set<Resource> alreadyUsed = log.getResourcesUtilizedWithin(log.getActivityStart(a), log.getActivityEnd(a), c);
				for (Resource r : alreadyUsed)
					for (Set<Resource> rs : possible)
						if (rs.contains(r))
							available.remove(rs);
				if (available.size() == 0) {
					return false;
				} else {
					int item = rng.nextInt(available.size());
					int i = 0;
					for (Set<Resource> r : available) {
						if (i == item) {
							log.setActivityResources(a, r);
							break;
						}
						i++;
					}
				}
			}
		}
		return true;
	}

	public ConcreteEventLog performFallbackRepair(ConcreteEventLog fixedLog) {
		LogGreedyFactory factory = new LogGreedyFactory(fixedLog.getAbstractLog());
		fixedLog = factory.generateRandomCandidate(new Random());

		if (!fixedLog.isLogSafe())
			System.err.println("Solution was still not safe after last resort repair!");

		return fixedLog;
	}//*/
	
	/*
	package au.edu.qut.bpm.genbinder.genetic.other;

import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import au.edu.qut.bpm.genbinder.genetic.genesis.LogGreedyFactory;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.Case;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public class LogRepairerSingleLog {

	public ConcreteEventLog RepairOneLog (ConcreteEventLog log) {
		
		ConcreteEventLog fixedLog = log.clone();
		if (!this.performTimeRepair(fixedLog) || !this.performResourceRepair(fixedLog))
			fixedLog = this.performFallbackRepair(fixedLog);

		return fixedLog;
		
	}
	public boolean performTimeRepair(ConcreteEventLog log) {
		// Time based repairs
		for (Case c : log.getAbstractLog().getCases()) {
			if (log.isCaseOrdered(c)) {
				// This case is ordered, but are there overlaps?
				if (log.isCaseNonOverlapping(c))
					continue;
				List<Activity> sortedTrace = log.getSortedTrace(c);
				long latestEnd = log.getActivityEnd(sortedTrace.get(0));
				for (int a = 1; a < sortedTrace.size(); a++) {
					if (log.getActivityStart(sortedTrace.get(a)) < latestEnd)
						log.setActivityStart(sortedTrace.get(a), latestEnd);
					latestEnd = log.getActivityEnd(sortedTrace.get(a));
				}
			} else {
				// This case is unordered, let's fix it
				List<Activity> newOrder = c.getOrderedTrace();
				for (int a = 0; a < newOrder.size(); a++) {
					Activity act = newOrder.get(a);
					long startTime = a == 0
							? c.getArrival()
							: log.getActivityEnd(act);
					log.setActivityStart(act, startTime);
				}
			}
		}
		return true;
	}

	public boolean performResourceRepair(ConcreteEventLog log) {
		// Resource based repairs
		Random rng = new Random(); // Meh...
		for (Case c : log.getAbstractLog().getCases()) {
			if (log.isCaseNonOverUtilizedResources(c))
				continue;
			for (Activity a : c.getActivities()) {
				Set<Set<Resource>> possible = log.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
				Set<Set<Resource>> available = new HashSet<Set<Resource>>(possible);
				Set<Resource> alreadyUsed = log.getResourcesUtilizedWithin(log.getActivityStart(a), log.getActivityEnd(a), c);
				for (Resource r : alreadyUsed)
					for (Set<Resource> rs : possible)
						if (rs.contains(r))
							available.remove(rs);
				if (available.size() == 0) {
					return false;
				} else {
					int item = rng.nextInt(available.size());
					int i = 0;
					for (Set<Resource> r : available) {
						if (i == item) {
							log.setActivityResources(a, r);
							break;
						}
						i++;
					}
				}
			}
		}
		return true;
	}

	public ConcreteEventLog performFallbackRepair(ConcreteEventLog fixedLog) {
		LogGreedyFactory factory = new LogGreedyFactory(fixedLog.getAbstractLog());
		fixedLog = factory.generateRandomCandidate(new Random());

		if (!fixedLog.isLogSafe())
			System.err.println("Solution was still not safe after last resort repair!");

		return fixedLog;
	}

}
====================================

package au.edu.qut.bpm.genbinder.genetic.mutation;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.uncommons.maths.number.ConstantGenerator;
import org.uncommons.maths.number.NumberGenerator;
import org.uncommons.watchmaker.framework.EvolutionaryOperator;

import au.edu.qut.bpm.genbinder.genetic.genesis.LogAbstractFactory;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public class LogResourceMutation implements EvolutionaryOperator<ConcreteEventLog> {
	private boolean performSafetyCheck = true;

	private final NumberGenerator<Integer> mutationCountVariable;
	private final NumberGenerator<Integer> mutationAmountVariable;

	public LogResourceMutation(boolean performSafetyCheck) {
		this(performSafetyCheck, 5, 15);
	}

	public LogResourceMutation(boolean performSafetyCheck, int mutationCount, int mutationAmount) {
		this(performSafetyCheck, new ConstantGenerator<Integer>(mutationCount), new ConstantGenerator<Integer>(mutationAmount));
	}

	public LogResourceMutation(boolean performSafetyCheck, NumberGenerator<Integer> mutationCount, NumberGenerator<Integer> mutationAmount) {
		this.performSafetyCheck = performSafetyCheck;
		this.mutationCountVariable = mutationCount;
		this.mutationAmountVariable = mutationAmount;
		
	}

	public List<ConcreteEventLog> apply(List<ConcreteEventLog> selectedCandidates, Random rng) {
		List<ConcreteEventLog> mutatedCandidates = new ArrayList<ConcreteEventLog>(selectedCandidates.size());
		for (ConcreteEventLog log : selectedCandidates)
			mutatedCandidates.add(mutate(log, rng));
		return mutatedCandidates;
	}

	private ConcreteEventLog mutate(ConcreteEventLog log, Random rng) {
		ConcreteEventLog newLog = log.clone();
		System.out.println("safeRes-" + this.performSafetyCheck);
		int mutationCount = Math.abs(mutationCountVariable.nextValue());
		while (mutationCount > 0) {
			int mutationAmount = Math.abs(mutationAmountVariable.nextValue());
			int c = rng.nextInt(newLog.getAbstractLog().getCases().size());
			while (mutationAmount > 0) {
				int a = rng.nextInt(newLog.getAbstractLog().getCases().get(c).getOrderedTrace().size());
				Activity act = newLog.getAbstractLog().getCases().get(c).getOrderedTrace().get(a);
				Set<Resource> newSet = null;
				if (performSafetyCheck)
					newSet = LogAbstractFactory.getRandomPossibleResourceSetForProposedStartTime(newLog, act, newLog.getActivityStart(act), rng);
				else
					newSet = LogAbstractFactory.getRandomResourceSet(newLog, act, rng);
				if (newSet != null)
					newLog.setActivityResources(act, newSet);
				--mutationAmount;
			}
			--mutationCount;
		}

		return newLog;
	}

	

}
==============

package au.edu.qut.bpm.genbinder.genetic.mutation;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.uncommons.maths.number.ConstantGenerator;
import org.uncommons.maths.number.NumberGenerator;
import org.uncommons.watchmaker.framework.EvolutionaryOperator;

import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.Case;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public class LogTimeShiftMutation implements EvolutionaryOperator<ConcreteEventLog> {
	private boolean performSafetyCheck = true;
	double delta = 1d;

	private final NumberGenerator<Integer> mutationCountVariable;
	private final NumberGenerator<Integer> mutationAmountVariable;

	public LogTimeShiftMutation(boolean performSafetyCheck) {
		this(performSafetyCheck, 3, 3);
	}

	public LogTimeShiftMutation(boolean performSafetyCheck, int mutationCount, int mutationAmount) {
		this(performSafetyCheck, new ConstantGenerator<Integer>(mutationCount),	new ConstantGenerator<Integer>(mutationAmount));
	}

	public LogTimeShiftMutation(boolean performSafetyCheck,	NumberGenerator<Integer> mutationCount,	NumberGenerator<Integer> mutationAmount) {
		this.performSafetyCheck = performSafetyCheck;
		this.mutationCountVariable = mutationCount;
		this.mutationAmountVariable = mutationAmount;
		
	}

	public List<ConcreteEventLog> apply(List<ConcreteEventLog> selectedCandidates, Random rng) {
		List<ConcreteEventLog> mutatedCandidates = new ArrayList<ConcreteEventLog>(selectedCandidates.size());
		for (ConcreteEventLog log : selectedCandidates) {
			mutatedCandidates.add(mutate(log, rng));
		}
		return mutatedCandidates;
	}

	private ConcreteEventLog mutate(ConcreteEventLog log, Random rng) {
		ConcreteEventLog newLog = log.clone();

		int mutationCount = Math.abs(mutationCountVariable.nextValue());
		while (mutationCount > 0) {
			int mutationAmount = Math.abs(mutationAmountVariable.nextValue());
			int c = rng.nextInt(newLog.getAbstractLog().getCases().size());
			Case cas = newLog.getAbstractLog().getCases().get(c);

			while (mutationAmount > 0) {
				List<Activity> trace = newLog.getSortedTrace(cas);
				int a = rng.nextInt(trace.size());
				Activity act = trace.get(a);
				System.out.println("safeTime-" + this.performSafetyCheck);
				if (performSafetyCheck) {
					long activityPossibleStartMin = (a == 0)
							? cas.getArrival()
							: newLog.getActivityEnd(trace.get(a - 1));
					long activityPossibleStartMax = (a == (trace.size() - 1))
							? (long) (newLog.getCaseEnd(cas) + act.getDuration() * delta)
							: newLog.getActivityStart(trace.get(a + 1)) - act.getDuration();
					long diff = activityPossibleStartMax - activityPossibleStartMin;
					long newStart = (diff <= 0)
							? activityPossibleStartMin
							: activityPossibleStartMin + (long) rng.nextInt((int) (diff));

					Set<Resource> usedRes = newLog.getResourcesUtilizedWithin(newStart, newStart + act.getDuration(), cas);
					boolean problem = false;
					for (Resource r : usedRes) {
						if (newLog.getActivityResources(act).contains(r)) {
							problem = true;
							break;
						}
					}
					if (!problem)
						newLog.setActivityStart(act, newStart);
				} else {
					long activityPossibleStartMin = (long) (newLog.getActivityStart(act) - (double) act.getDuration() * delta);
					long activityPossibleStartMax = (long) (newLog.getActivityStart(act) + (double) act.getDuration() * delta);
					if (activityPossibleStartMin <= newLog.getCaseArrival(cas))
						activityPossibleStartMin = newLog.getCaseArrival(cas);
					long newStart = activityPossibleStartMin + (long) rng.nextInt((int) (activityPossibleStartMax - activityPossibleStartMin));
					newLog.setActivityStart(act, newStart);
				}
				--mutationAmount;
			}
			--mutationCount;
		}

		return newLog;
	}

}
===============

package au.edu.qut.bpm.genbinder.genetic.genesis;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import org.uncommons.watchmaker.framework.factories.AbstractCandidateFactory;

import au.edu.qut.bpm.genbinder.models.AbstractLog;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public abstract class LogAbstractFactory extends
		AbstractCandidateFactory<ConcreteEventLog> {
	protected AbstractLog templateLog;

	public LogAbstractFactory(AbstractLog log) {
		this.templateLog = log;
	}

	public abstract ConcreteEventLog generateRandomCandidate(Random rng);

	public static Set<Resource> getRandomPossibleResourceSetForProposedStartTime(ConcreteEventLog newLog, Activity a, long start, Random rng) {
		Set<Set<Resource>> possible = newLog.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
		Set<Set<Resource>> available = new HashSet<Set<Resource>>(possible);
		Set<Resource> alreadyUsed = newLog.getResourcesUtilizedWithin(start, start + newLog.getActivityDuration(a), a.getCase());

		for (Resource r : alreadyUsed)
			for (Set<Resource> rs : possible)
				if (rs.contains(r))
					available.remove(rs);

		if (available.size() == 0) {
			return null;
		} else {
			int item = rng.nextInt(available.size());
			int i = 0;
			for (Set<Resource> r : available) {
				if (i == item)
					return r;
				i++;
			}
		}

		return null;
	}
	
	public static Set<Resource> getRandomResourceSet(ConcreteEventLog newLog, Activity a, Random rng) {
		Set<Set<Resource>> possible = newLog.getAbstractLog().getTaskResourceSetMap().get(a.getTask());
		int item = rng.nextInt(possible.size());
		int i = 0;
		for (Set<Resource> r : possible) {
			if (i == item)
				return r;
			i++;
		}
		return null;
	}

}
=========

package au.edu.qut.bpm.genbinder.genetic.genesis;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import au.edu.qut.bpm.genbinder.models.AbstractLog;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.Case;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public class LogGreedyFactory extends LogAbstractFactory {

	public LogGreedyFactory(AbstractLog log) {
		super(log);
	}

	public ConcreteEventLog generateRandomCandidate(Random rng) {
		ConcreteEventLog newLog = new ConcreteEventLog(templateLog);
		Set<Activity> scheduledActivities = new HashSet<Activity>();

		for (Case c : newLog.getAbstractLog().getCases()) {
			boolean first = true;
			long placeAfter = 0;
			if (first)
				placeAfter = c.getArrival();
			first = false;
			for (Activity a : c.getOrderedTrace()) {
				// Find the smallest start time
				Set<Resource> usedAtProposal;
				// Start with possible minimum
				usedAtProposal = getRandomPossibleResourceSetForProposedStartTime(newLog, a, placeAfter, rng);
				if (usedAtProposal == null) {
					boolean scheduled = false;
					// Use already scheduled activities to discretize problem
					for (Activity oa : scheduledActivities) {
						if (newLog.getActivityEnd(oa) >= placeAfter) {
							usedAtProposal = getRandomPossibleResourceSetForProposedStartTime(newLog, a, newLog.getActivityEnd(oa), rng);
							if (usedAtProposal != null) {
								newLog.setActivityStart(a, newLog.getActivityEnd(oa));
								newLog.setActivityResources(a, usedAtProposal);
								scheduled = true;
								break;
							}
						}
					}
					if (!scheduled)
						System.err.println("An activity could not be greedily scheduled: you should panic");
				} else {
					// Good news
					newLog.setActivityStart(a, placeAfter);
					newLog.setActivityResources(a, usedAtProposal);
				}
				placeAfter = newLog.getActivityEnd(a);
				scheduledActivities.add(a);
			}
		}

		return newLog;
	}

}
===========

package au.edu.qut.bpm.genbinder.genetic.genesis;

import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import au.edu.qut.bpm.genbinder.genetic.evaluation.costmodels.CostCalculations;
import au.edu.qut.bpm.genbinder.genetic.other.LogRepairerSingleLog;
import au.edu.qut.bpm.genbinder.models.AbstractLog;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.Case;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;
import au.edu.qut.bpm.genbinder.models.Resource;

public class LogRandomizedFactory extends LogAbstractFactory {

	public LogRandomizedFactory(AbstractLog log) {
		super(log);
	}

	public ConcreteEventLog generateRandomCandidate(Random rng) {
		// Create a new solution (valid)
		ConcreteEventLog newLog;
		final LogRepairerSingleLog repair = new LogRepairerSingleLog();
		
		int x = 0;
		while (true) {
			boolean restart = false;
			newLog = new ConcreteEventLog(templateLog);
			System.out.println("random" + x++);
			// Randomize the starts
			for (Case c : newLog.getAbstractLog().getCases()) {
				long randomizeAfter = c.getArrival();
				for (Activity a : c.getOrderedTrace()) {
					// TODO: Set better gap?
					long gap = (long) Math.ceil(rng.nextFloat() * a.getDuration() * 2);
					newLog.setActivityStart(a, randomizeAfter + gap);
					randomizeAfter = newLog.getActivityEnd(a);
				}
			}

			// Randomize the resources, restart if this clashes
			for (Case c : newLog.getAbstractLog().getCases()) {
				if (restart)
					break;
				for (Activity a : c.getActivities()) {
					if (restart)
						break;
					//Set<Resource> usedAtProposal = getRandomPossibleResourceSetForProposedStartTime(newLog, a, newLog.getActivityStart(a), rng);//safe
					Set<Resource> usedAtProposal = getRandomResourceSet(newLog, a, rng);//unsafe
					newLog.setActivityResources(a, usedAtProposal);
				
					if (usedAtProposal == null) {
						// TODO: Note that this could potentially take very long
						// for tight problems. Maybe devise a better method
						// (combined with fallback from repair approach?)
						restart = true;
					} else {
						newLog.setActivityResources(a, usedAtProposal);
					}
				}
			}
			if (!restart)
				break;

		} // End forever

		return repair.RepairOneLog(newLog);//make it safe after unsafe operation
	}
	
}
=========
package au.edu.qut.bpm.genbinder.genetic.genesis;

import java.util.Random;

import au.edu.qut.bpm.genbinder.models.AbstractLog;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;

public class LogRandomizedGreedyFactory extends LogAbstractFactory{

	public LogRandomizedGreedyFactory(AbstractLog log) {
		super(log);
	}

	public ConcreteEventLog generateRandomCandidate(Random rng) {
		ConcreteEventLog newLog = new ConcreteEventLog(templateLog);
		
		LogRandomizedFactory randomFact = new LogRandomizedFactory(newLog.getAbstractLog());
		newLog = randomFact.generateRandomCandidate(new Random());
		
		LogGreedyFactory greedyFact = new LogGreedyFactory(newLog.getAbstractLog());
		newLog = greedyFact.generateRandomCandidate(new Random());

		return newLog;
	}

	
}
===========
package au.edu.qut.bpm.genbinder.genetic.crossover;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.uncommons.maths.number.ConstantGenerator;
import org.uncommons.maths.number.NumberGenerator;
import org.uncommons.watchmaker.framework.operators.AbstractCrossover;

import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;

public class LogActivitiesCrossover extends AbstractCrossover<ConcreteEventLog> {
	private boolean performSafetyCheck = true;
	private int maxNrTries = 50;

	public LogActivitiesCrossover(boolean performSafetyCheck) {
		this(performSafetyCheck, 2);
	}

	public LogActivitiesCrossover(boolean performSafetyCheck, int crossoverPoints) {
		this(performSafetyCheck, new ConstantGenerator<Integer>(crossoverPoints));
	}

	public LogActivitiesCrossover(boolean performSafetyCheck, NumberGenerator<Integer> crossoverPointsVariable) {
		super(crossoverPointsVariable);
		this.performSafetyCheck = performSafetyCheck;
	}

	@Override
	protected List<ConcreteEventLog> mate(ConcreteEventLog parent1, ConcreteEventLog parent2, int numberOfCrossoverPoints, Random rng) {
		ConcreteEventLog offspring1 = parent1.clone();
		ConcreteEventLog offspring2 = parent2.clone();

		List<Activity> activities = new ArrayList<Activity>(offspring1.getAbstractLog().getActivities());

		int nrRestarts = 0;
		while (true) {
			boolean safeResult = true;
			for (int ncr = 0; ncr < numberOfCrossoverPoints; ncr++) {
				int crossoverpoint = rng.nextInt(activities.size() - 1) + 1;
				for (int i = 0; i < crossoverpoint; i++) {
					copyBinding(offspring2, offspring1, activities.get(i));
					copyBinding(offspring1, offspring2, activities.get(i));
				}
				if (performSafetyCheck && (!offspring1.isLogSafe() || !offspring2.isLogSafe())) {
					safeResult = false;
					break;
				}
			}
			if (safeResult || !performSafetyCheck)
				break; // We've found a solution
			nrRestarts++;
			if (nrRestarts > maxNrTries) { // Just give up
				offspring1 = parent1.clone();
				offspring2 = parent2.clone();
				break;
			}
		}

		List<ConcreteEventLog> result = new ArrayList<ConcreteEventLog>(2);
		result.add(offspring1);
		result.add(offspring2);
		return result;
	}

	private void copyBinding(ConcreteEventLog from, ConcreteEventLog to, Activity activity) {
		to.setActivityStart(activity, from.getActivityStart(activity));
		to.setActivityResources(activity, from.getActivityResources(activity));
	}

}

	*/
}
